#include "Game.h"

#include "GUI/guiWindow.h"
#include "GUI/guiButton.h"

const int KILOS = 1000;



bool Game::m_quit;
const float Game::SPEED = 10.0f;
scene::ICameraSceneNode* Game::camera = NULL;


IrrlichtDevice* Game::s_Device;
irr::newton::ICameraBodyFPS* Game::s_CameraBody;
irr::newton::IWorld* Game::s_World;
Facets::Player* Game::s_Player;
irr::gui::IGUIFont* Game::s_Font;
double Game::s_rot;

void Game::Execute() {
	using namespace irr;
	using namespace scene;
	
	video::E_DRIVER_TYPE driverType;
	
	driverType = video::EDT_OPENGL;
	
	// create s_Device and exit if creation failed
	core::dimension2di videoDim ( 640, 480 );

	s_Device = createDevice(driverType, videoDim, 32, false );

	if (s_Device == 0)
		return; // could not create selected driver.

	Facets::Logger::Initialize(s_Device->getLogger());
	
	/*
	Get a pointer to the video driver and the SceneManager so that
	we do not always have to write s_Device->getVideoDriver() and
	s_Device->getSceneManager().
	*/
	video::IVideoDriver* driver = s_Device->getVideoDriver();
	scene::ISceneManager* smgr = s_Device->getSceneManager();
	gui::IGUIEnvironment* env = s_Device->getGUIEnvironment();
	guiFactory::Instantiate(env);
	
	gui::IGUISkin* tmpskin = env->getSkin();
	gui::IGUIFont* tmpfont = env->getFont("fonts/Qlassik14.xml");
	tmpskin->setFont(tmpfont,irr::gui::EGDF_DEFAULT);

	gui::IGUIImage* tmpimg = env->addImage(driver->getTexture("HexhackersLogo.PNG"),
			core::position2d<int>(0,5));
	tmpimg->setScaleImage(true);
	core::dimension2di tmpdim = 
		core::dimension2di(
			(tmpimg->getAbsoluteClippingRect().LowerRightCorner.X - tmpimg->getAbsoluteClippingRect().UpperLeftCorner.X),
			(tmpimg->getAbsoluteClippingRect().LowerRightCorner.Y - tmpimg->getAbsoluteClippingRect().UpperLeftCorner.Y));
			
	tmpdim.Width *= .25; tmpdim.Height *= .25;
	tmpimg->setMaxSize(tmpdim);
	
    camera = smgr->addCameraSceneNode();
	camera->setPosition(core::vector3df(0,0,0));
	
	//tekNode->getMaterial(0).Shininess = 20.0f; // set size of specular highlights
	
	smgr->addLightSceneNode(0,core::vector3df(300.0f,1500.0f,0.0f),video::SColorf(255,255,255,128),3,-1);
	/*
		add the geometry mesh to the Scene ( polygon & patches )
		The Geometry mesh is optimised for faster drawing
	*/
	
/*	
	scene::ITerrainSceneNode* node = smgr->addTerrainSceneNode("heightmap.bmp",
			0,-1,core::vector3df(camera->getPosition().X-1000.0f,
					camera->getPosition().Y-200.0f,camera->getPosition().Z-1000.0f),
			core::vector3df(0,0,0),core::vector3df(20.0f,8.0f,20.0f),
			video::SColor(255, 255, 255, 255),5,scene::ETPS_33,1,false);
	node->setMaterialFlag(video::EMF_LIGHTING, true);
	node->setMaterialTexture(0, driver->getTexture(
	   "neutral-stone.jpg"));
	node->setMaterialTexture(1, driver->getTexture(
	   "mossyrock.jpg"));
	node->setMaterialType(video::EMT_DETAIL_MAP);
	node->scaleTexture(1.0f, 40.0f);
 */
	irr::newton::IMaterial* camera_material;
	irr::newton::IMaterial* terrain_material;
	
	camera->setFarValue(12000.0f);

	//PHYSICS
	//create physics world
	s_World=irr::newton::createPhysicsWorld(s_Device);

	scene::IAnimatedMesh* world_mesh_anim = smgr->getMesh("media/island1.b3d");
	
	assert(world_mesh_anim != NULL);
	
	printf("world_mesh_anim finished\n");
	
	//create the scene node
	scene::ISceneNode* world_node =	smgr->addOctTreeSceneNode(world_mesh_anim->getMesh(0));
		
	printf("world_node oct-tree created\n");
	
	world_node->setMaterialFlag(video::EMF_LIGHTING, true);
	
	printf("setting materials complete\n");
	
	//position the scene node
	world_node->setPosition(core::vector3df(45,-50,0));
	world_node->setScale(core::vector3df(5,5,5));
	
	printf("world_node finished\n");
	
	//let's create the body for our map
	//if we don't do this, the ellipsoid trought the map
	//the creation methos is the same
	irr::newton::SBodyFromNode mapData;
	mapData.Node = world_node;
	//because the node is a oct tree scene node and not a simple scene node we need to pass the mesh also
	mapData.Mesh = world_mesh_anim->getMesh(0);

	mapData.Type = newton::EBT_TREE;
	//mapData.BodyScaleOffsetFromNode = core::vector3df(5,5,5);
	
	printf("mapData finished\n");
	
	//create the body
	irr::newton::IBody* terrain_body = s_World->createBody(mapData);

	//END OF INIT PHISICS

	printf("terrain_body done\n");
	terrain_material=s_World->createMaterial();
	camera_material=s_World->createMaterial();

	//set materials to their bodies
//	s_CameraBody->setMaterial(camera_material);
	terrain_body->setMaterial(terrain_material);
	
	camera_material->setCollidable(terrain_material,false);
	
	camera->setPosition(core::vector3df(camera->getPosition().X+500.0f,camera->getPosition().Y,camera->getPosition().Z+500.0f));
		
	Facets::Object* tekkblade = new Facets::Entity(camera->getPosition(),core::vector3df(1,0,0), 25);
	dynamic_cast<Facets::Entity*>(tekkblade)->loadModel(core::stringc("tekkblade.xml"));
	dynamic_cast<Facets::Entity*>(tekkblade)->setAnimation(EMAT_RUN);
	
	Facets::Object* marines[10];
	for(int zzz = 0; zzz < 10; zzz++) {
		marines[zzz] = new Facets::Entity(camera->getPosition(),core::vector3df(1,0,0), 25);
		dynamic_cast<Facets::Entity*>(marines[zzz])->loadModel(core::stringc("marine.xml"));
		dynamic_cast<Facets::Entity*>(marines[zzz])->setAnimation(EMAT_RUN);
	}
	
	tekkblade->setPosition(core::vector3df(camera->getPosition().X+40.0f,camera->getPosition().Y+40.0f,camera->getPosition().Z));
	for(int zzz = 0; zzz < 2; zzz++) {
		for(int yyy = 0; yyy < 5; yyy++) {
			marines[zzz+yyy*2]->setPosition(core::vector3df(camera->getPosition().X+(60.0f*zzz),camera->getPosition().Y+20.0f,camera->getPosition().Z+40.0f*yyy));
		}
	}
	
	distance = 15000.0f;
	
	//s_Device->getCursorControl()->setVisible(false);
			
	u32 timeElapsed = 0;
	u32 lastTime = s_Device->getTimer()->getRealTime();
	
	s_Player = new Facets::Player(
			camera->getPosition(),
			core::vector3df(1,0,0), 25);
	//dynamic_cast<Facets::Entity*>(
	s_Player->loadModel(core::stringc("test.xml"));
	//dynamic_cast<Facets::Entity*>(
	s_Player->setAnimation(EMAT_RUN);

	s_Player->setPosition(core::vector3df(camera->getPosition().X+40.0f,camera->getPosition().Y+400.0f,camera->getPosition().Z));
	
	// create an event receiver for making screenshots
	EventCatcher myCatcher = EventCatcher(s_Device);
	boost::shared_ptr<EventHandler> tempPtr(new KeyHandler);
	boost::shared_ptr<EventHandler> tempPtr2(new ScreenshotHandler("testSS"));
	
	myCatcher.RegisterEventHandler(tempPtr);
	myCatcher.RegisterEventHandler(tempPtr2);
	
	s_Device->setEventReceiver ( &myCatcher );

	
	s_World->setMinimumFrameRate(60.0f);

	camera->setPosition(core::vector3df(camera->getPosition().X,camera->getPosition().Y+200.0f,camera->getPosition().Z));	
	
	guiWindow* mywin = new guiWindow(60,60,120,120,false,L"LOLOL");
	guiButton* mybutton = new guiButton(0,20,40,20,L"LOLOL",mywin);
	guiButton* lol = new guiButton(330,280,80,80,L"Uuuu...");
	

	TitleCompositeNode* fff = Game::CreateTitleCompositeNode(dynamic_cast<Facets::Entity*>(s_Player)->getNode());
	fff->addBar(L"Health",TCN_NORMAL_BAR);	
	
	while(!m_quit && s_Device->run())
	if (s_Device->isWindowActive())
	{	
		static double rot_val = 0.0f;
		
		timeElapsed = (s_Device->getTimer()->getRealTime()-lastTime)/1000.0f;

		rot_val += 0.025f*timeElapsed*Game::s_rot;

		//update physics
		//s_World->update(timeElapsed*2000.0f);
		s_World->update(timeElapsed);
		
		//camera->getRotation()
		driver->beginScene(true, true, video::SColor(255,20,20,40));
		smgr->drawAll();
		env->drawAll();
		
		for(int zzz = 0; zzz < 10; zzz++) {
				marines[zzz]->update(timeElapsed);
		}
		tekkblade->update(timeElapsed);
		
		s_Player->update(timeElapsed);
		core::vector3df playpos = s_Player->getPosition();
		camera->setTarget(playpos);
		playpos.X-=100.0f*sin(rot_val);
		playpos.Y+=20.0f;
		playpos.Z-=100.0f*cos(rot_val);
		camera->setPosition(playpos);
				
		driver->endScene();
	}

	delete s_Player;
	
	for(int zzz = 0; zzz < 10; zzz++) {
			delete marines[zzz];
	}

	delete tekkblade;

	delete mywin;
	delete mybutton;
	delete lol;	

	
	s_World->destroyWorld();

	/*
	In the end, delete the Irrlicht s_Device.
	*/
	s_Device->drop();
}

scene::IAnimatedMeshSceneNode* Game::CreateMeshNode(const core::stringc& filename) {
	scene::IAnimatedMesh* mesh = Game::s_Device->getSceneManager()->getMesh(filename.c_str());
	if(!mesh)
		Facets::Logger::Instance()->log(filename.c_str(),"Null mesh.");
	scene::IAnimatedMeshSceneNode* temp = Game::s_Device->getSceneManager()->addAnimatedMeshSceneNode(mesh);
	if(!temp)
		Facets::Logger::Instance()->log(filename.c_str(),"Null scene node.");
	return temp;
}

scene::ITextSceneNode* Game::CreateTextNode(const core::stringw& text, const core::vector3df& loc, bool scaling, scene::ISceneNode* par, irr::core::dimension2df size) {
	if(!Game::s_Font)
		Game::s_Font = s_Device->getGUIEnvironment()->getFont("fonts/Qlassik26.xml");
	if(size.Width == 0 || size.Height == 0) {
		irr::core::dimension2di tmp = Game::s_Font->getDimension(text.c_str());
		size.Width = tmp.Width/4;
		size.Height = tmp.Height/4;
	}
	scene::ITextSceneNode* mesh;
	if(scaling) { 
		mesh = Game::s_Device->getSceneManager()->addBillboardTextSceneNode(Game::s_Font,text.c_str(),par,size,loc,-1,
				irr::video::SColor(255,255,255,255),irr::video::SColor(255,255,255,255)); 
		mesh->setMaterialFlag(video::EMF_ZBUFFER, true); 
	}
	else {
		mesh = Game::s_Device->getSceneManager()->addTextSceneNode(Game::s_Font, text.c_str(),irr::video::SColor(255,255,255,128),par,loc,-1);
	}
	if(!mesh)
		Facets::Logger::Instance()->log(core::stringc(text.c_str()).c_str(),"Null text scene node.");
	return mesh;
}

TitleCompositeNode* Game::CreateTitleCompositeNode(irr::scene::ISceneNode* parent, int id) {
	if(!parent)
		parent = Game::s_Device->getSceneManager()->getRootSceneNode();
	return new TitleCompositeNode(parent,Game::s_Device->getSceneManager(),Game::s_Device->getSceneManager()->getSceneCollisionManager(),id);
}